<?php

final class Loader {

    protected $registry;

    public function __construct() {
        $this->registry = Registry::getInstance();
    }

    /**
     *
     * @param type $view
     *  view которую необходимо подключить, если она уже была подключена,
     *  ничего оне происходит.
     * @return type
     */
    /* public function view($view) {

      $file = 'class.' . $view . 'View.php';

      if (in_array($file, $this->registry->includedfiles))
      return;

      foreach (new DirectoryIterator(DIR_APPLICATION) as $dir) {
      if ($dir->isDot() || $dir->isFile() || $dir->getBasename() == '.svn')
      continue;
      foreach (new DirectoryIterator($dir->getPath() . "/" . $dir->getBasename() . '/View') as $dir2) {
      if ($dir2->isDot())
      continue;
      if ($dir2->isFile()) {
      if ($dir2->getBasename() == $file) {
      $this->registry->set('includedfiles', array_merge($this->registry->includedfiles, array($file)));
      require_once $dir2->getPath() . '/' . $dir2->getBasename();
      return;
      }
      }
      }
      }
      trigger_error('Error: Could not load view ' . $view . '!');
      exit();
      }

      public function controller($path) {
      require_once $path;
      } */


    public function library($library) {

        $file = DIR_SYSTEM . 'lib/class.' . $library . '.php';
        if (in_array($file, $this->registry->includedfiles))
            return;
        if (file_exists($file)) {
            $this->registry->set('includedfiles', array_merge($this->registry->includedfiles, array($file)));
            include_once($file);
        } else {
            trigger_error('Error: Could not load library ' . $library . '!');
            exit();
        }
    }

    /*
      public function model($model) {

      $file = 'class.' . $model . 'Model.php';
      $class = preg_replace('/[^a-zA-Z0-9]/', '', $model) . 'Model';

      if (isset($this->registry->{'model_' . $model}))
      return;

      $flag = false;
      foreach (new DirectoryIterator(DIR_APPLICATION) as $dir) {
      if ($dir->isDot() || $dir->isFile() || $dir->getBasename() == '.svn')
      continue;
      foreach (new DirectoryIterator($dir->getPath() . "/" . $dir->getBasename() . '/Model') as $dir2) {
      if ($dir2->isDot())
      continue;
      if ($dir2->isFile()) {
      if ($dir2->getBasename() == $file) {
      require_once $dir2->getPath() . '/' . $dir2->getBasename();
      $flag = false;
      break;
      }
      }
      }
      if ($flag)
      break;
      }
      $this->registry->set('model_' . $model, new $class($this->registry));
      } */

    /**
     * Загружает все компоненты из папки компонентов 
     */
    public function init_components() {

        $components_data = array();
        // папка компонентов
        $iter = new DirectoryIterator(DIR_COMPONENTS);
        foreach ($iter as $dir_places) {

            if ($dir_places->isDot() || $dir_places->getBasename() == '.svn')
                continue;

            foreach (new DirectoryIterator($dir_places->getPath() . "/" . $dir_places->getBasename() . '') as $dir_components) {
                if ($dir_components->isDot() || $dir_components->getBasename() == '.svn')
                    continue;
                if ($dir_components->isDir()) {

                    $fp = fopen($dir_places->getPath() . "/" . $dir_places->getBasename() . '/' . $dir_components->getBasename() . '/info.cfg', 'r');

                    $component_paths_to_mvc = array();
                    $component_info = array();

                    while (!feof($fp)) {
                        $str = fgets($fp);
                        //echo $str . '<br>';
                        if ($str[0] != "#" && trim($str) != "") {

                            if (preg_match('/^((?:CONTROLLERS)|(?:MODELS)|(?:VIEWS)):([\D]+)$/ui', $str, $res)) {
                                //$res[1] - название (CONTROLLER|VIEWS|MODELS)
                                //$res[2] - пути до классов
                                $paths = array();
                                $paths = explode(',', $res[2]);
                                foreach ($paths as $key => $path) {
                                    $path = trim($path);
                                    if (!empty($path))
                                        $paths[$key] = $dir_places->getBasename() . '/' . $dir_components->getBasename() . '/' . $path;
                                }
                                $component_paths_to_mvc[strtolower($res[1])] = $paths;
                            }
                            if (preg_match('/^((?:MACHINE-NAME)|(?:VERSION)|(?:MAIN-CONTROLLER)):\s*([\w\s\d.]+\s*)$/ui', $str, $res)) {
                                //$res[1] - название переменной
                                //$res[2] - пути до классов
                                $value = trim($res[2]);

                                if (empty($value)) {
                                    trigger_error('Component data not found! - ' . trim(strtolower($res[1])) . '!');
                                    exit();
                                }
                                $key = trim(strtolower($res[1]));
                                $component_info[trim(strtolower($res[1]))] = ($key != 'main-controller' ? strtolower($value) : $value);
                            }
                        }
                    }

                    fclose($fp);
                }
                if (!isset($component_info['machine-name'])) {
                    trigger_error('Machine name not found for component!');
                    exit();
                }
                $components_data[$component_info['machine-name']] = $component_info;
                $components_data[$component_info['machine-name']]['mvc'] = $component_paths_to_mvc;
                unset($components_data[$component_info['machine-name']]['machine-name']);
            }
        }
        $this->registry->set('components', $components_data);
        return $components_data;
    }

    public function component($machine_name) {

        $components = $this->registry->components;

        if (empty($components)) {
            trigger_error('Components not init');
            exit();
        }

        if (!isset($components[$machine_name])) {
            trigger_error('Component not found');
            exit();
        }

        $component = $this->registry->components[$machine_name];

//        echo '<pre>'; var_dump($this->registry->components); echo '</pre>'; 

        foreach ($component['mvc']['controllers'] as $controller) {
            if (file_exists(DIR_COMPONENTS . $controller))
                require_once DIR_COMPONENTS . $controller;
            else {
                trigger_error("Controller of " . $machine_name . " does not exists");
                exit();
            }
        }

        foreach ($component['mvc']['models'] as $model) {
            if (file_exists(DIR_COMPONENTS . $model))
                require_once DIR_COMPONENTS . $model;
//            else
//            {
//                trigger_error("Model of " . $machine_name .  " does not exists");
//                //exit();
//            }
        }


        foreach ($component['mvc']['views'] as $view) {
            if (file_exists(DIR_COMPONENTS . $view))
                require_once DIR_COMPONENTS . $view;
//            else
//            {
//                trigger_error("View of " . $machine_name .  " does not exists");
//                exit();
//            }
        }

//        foreach($component['mvc'] as $mvc)
//        {
//            foreach($mvc as $item)
//            {
//                require_once DIR_COMPONENTS . $item;
//            }
//        }
    }

    /**
     * Загружает все включенные модули
     */
    public function init_modules() {
        $modules_data = array();
        
        $cfg = $this->registry->get('config');
        $iter = new DirectoryIterator(DIR_MODULES);
        foreach ($iter as $dir_owner) {

            if ($dir_owner->isDot() || $dir_owner->getBasename() == '.svn')
                continue;
            if ($dir_owner->isDir())
                foreach (new DirectoryIterator($dir_owner->getPath() . "/" . $dir_owner->getBasename() . '') as $dir_modules) {
                    if ($dir_modules->isDot() || $dir_modules->getBasename() == '.svn')
                        continue;
                    $modules_mvc = array('controller' => array(), 'view' => array(), 'model' => array());
                    $hooks = array();
                    if (in_array($dir_modules, $cfg['defmodules']) || in_array($dir_modules, $cfg['usermodules']))
                        foreach (new DirectoryIterator($dir_modules->getPath() . "/" . $dir_modules->getBasename() . '') as $dir_mvc) {
                            if ($dir_mvc->isDot() || $dir_mvc->getBasename() == '.svn')
                                continue;
                            if ($dir_mvc->isDir()) {
                                foreach (new DirectoryIterator($dir_mvc->getPath() . "/" . $dir_mvc->getBasename() . '') as $classname) {

                                    if ($classname->isFile() && preg_match('/^(class).([a-z_A-Z]+).(php)$/', $classname, $matches) && file_exists($classname->getPath() . '/' . $classname->getBaseName())) {
                                        require_once ($classname->getPath() . '/' . $classname->getBaseName());
                                        $methods = get_class_methods($matches[2]);
//                                        echo $matches[2].'<br>';
                                        $methods = array_filter($methods, function ($item) use (&$methods) {
                                                    $pair = each($methods);
                                                    return preg_match('/^(hook)_([a-z_A-Z]+)$/', $pair[1]);
                                                });
                                          $hooks[$matches[2]] = $methods;
//                                        echo '<pre>';
//                                        var_dump($methods);
//                                        echo '</pre>';
                                        
                                        $this->registry->set('includedfiles', array_merge($this->registry->includedfiles, array($classname->getBaseName())));
                                        $modules_mvc[strtolower($dir_mvc->getBasename())][] = $classname->getPath() . '/' . $classname->getBasename();
//                                 echo '<pre>';
//                                var_dump($modules_mvc);
//                                echo '</pre>';
                                        $modules_data[strtolower($dir_modules->getBasename())]['mvc'] = $modules_mvc;
                                        $modules_data[strtolower($dir_modules->getBasename())]['hooks'] = $hooks;
                                    }
                                }
                            }
                        }
                }
        }
        $this->registry->set('modules', $modules_data);
//        echo '<pre>'; var_dump($modules_data); echo '</pre>'; 
    }

}

?>